1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.util.system; 12 13 import hip.util.conv; 14 import hip.util.string:fromStringz, toStringz; 15 import hip.util.path:pathSeparator; 16 17 version(PSVita) version = NoSharedLibrarySupport; 18 version(WebAssembly) version = NoSharedLibrarySupport; 19 version(CustomRuntimeTest) version = NoSharedLibrarySupport; 20 version(Android) version = NoSharedLibrarySupport; 21 version(iOS) version = NoSharedLibrarySupport; 22 23 version(Windows) 24 { 25 pragma(lib, "psapi.lib"); 26 pragma(lib, "dbghelp.lib"); 27 private struct MODLOAD_DATA {DWORD ssize; DWORD ssig; PVOID data; DWORD size; DWORD flags; } 28 import hip.util.windows; 29 extern(Windows) private 30 { 31 alias SymUnloadModule = SymUnloadModule64; 32 BOOL SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); 33 DWORD64 SymLoadModuleEx( 34 HANDLE hProcess, 35 HANDLE hFile, 36 PCSTR ImageName, 37 PCSTR ModuleName, 38 DWORD64 BaseOfDll, 39 DWORD DllSize, 40 MODLOAD_DATA* Data, 41 DWORD Flags 42 ); 43 BOOL SymRefreshModuleList(HANDLE hProcess); 44 45 } 46 } 47 enum debugger = "asm {int 3;}"; 48 49 string sanitizePath(string path) @safe pure nothrow 50 { 51 version(Windows) 52 return path; 53 else 54 { 55 import hip.util.string; 56 if(indexOf(path, '\\') == -1) 57 return path; 58 return replaceAll(path, '\\', "/"); 59 } 60 } 61 bool isPathUnixStyle(string path) @safe pure nothrow 62 { 63 for(size_t i = 0; i < path.length; i++) 64 if(path[i] == '/') 65 return true; 66 return false; 67 } 68 string buildPath(string[] args...) @safe pure nothrow 69 { 70 if(args.length == 0) 71 return null; 72 string ret; 73 for(int i = 0; i < cast(int)args.length-1; i++) 74 ret~= args[i]~pathSeparator; 75 return ret~args[$-1]; 76 } 77 78 version(Windows) 79 { 80 // import core.sys.windows.winbase; 81 // import core.sys.windows.windef; 82 83 import hip.util.windows; 84 85 private HMODULE moduleHandle; 86 extern(Windows) nothrow @system void* dll_import_var(string name) 87 { 88 if(moduleHandle == null) 89 moduleHandle = GetModuleHandle(null); 90 return GetProcAddress(moduleHandle, (name~"\0").ptr); 91 } 92 string[] dllImportVariables(Args...)() 93 { 94 import std.traits:isFunctionPointer; 95 string[] failedFunctions; 96 static foreach(a; Args) 97 { 98 static assert(isFunctionPointer!a, "Can't dll import a non function pointer ( "~a.stringof~" )"); 99 a = cast(typeof(a))dll_import_var(a.stringof); 100 if(a is null) 101 failedFunctions~= a.stringof; 102 } 103 return failedFunctions; 104 } 105 106 string getLastWindowsErrorMessage() 107 { 108 return getWindowsErrorMessage(GetLastError()); 109 } 110 111 string getWindowsErrorMessage(HRESULT hr) 112 { 113 wchar* buffer; 114 HRESULT fmt = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 115 FORMAT_MESSAGE_IGNORE_INSERTS | 116 FORMAT_MESSAGE_ALLOCATE_BUFFER, 117 null, hr, 0u, cast(LPWSTR)&buffer, 0, null); 118 119 if(fmt == 0) 120 return "Error code '"~hip.util.conv.toString(hr)~"' not found"; 121 string ret = fromUTF16(cast(wstring)buffer[0..fmt]); 122 123 LocalFree(buffer); 124 125 return ret; 126 } 127 128 void winEnforce(scope BOOL delegate() dg, scope string message) 129 { 130 if(!dg()) 131 throw new Error(message~": "~getWindowsErrorMessage(GetLastError())); 132 } 133 } 134 135 136 /** 137 * 138 * Params: 139 * libName = Basically a path 140 * Returns: libName appended with the dynamic library extension 141 */ 142 string dynamicLibraryGetLibName(string libName) 143 { 144 version(NoSharedLibrarySupport) return ""; 145 else version(Windows) return libName~".dll"; 146 else version(Posix) 147 { 148 import hip.util.path; 149 libName.filename = "lib"~libName.filename~".so"; 150 return libName; 151 } 152 else static assert(0, "Platform not supported"); 153 } 154 155 bool dynamicLibraryIsLibNameValid(string libName) 156 { 157 version(NoSharedLibrarySupport) 158 return true; 159 else version(Windows) 160 return libName[$-4..$] == ".dll"; 161 else version(Posix) 162 { 163 import hip.util.path; 164 return libName.filename[0..3] == "lib" && libName[$-3..$] == ".so"; 165 } 166 } 167 168 version(NoSharedLibrarySupport) 169 { 170 void* dynamicLibraryLoad(string libName) { return null; } 171 } 172 else 173 ///It will open the current executable if libName == null 174 void* dynamicLibraryLoad(string libName) 175 { 176 void* ret; 177 if(libName == null) 178 { 179 version(Windows) 180 { 181 ret = GetModuleHandle(null); 182 } 183 else version(linux) 184 { 185 import core.sys.posix.dlfcn : dlopen, RTLD_NOW; 186 ret = dlopen(null, RTLD_NOW); 187 } 188 } 189 else 190 { 191 version (OSX) {} //OSX gives an error with rt_loadLibrary not found. 192 else 193 { 194 import core.runtime; 195 ret = Runtime.loadLibrary(libName); 196 version(Windows) 197 { 198 import core.sys.windows.psapi; 199 import core.sys.windows.winbase; 200 MODULEINFO moduleInfo; 201 202 winEnforce(() => GetModuleInformation(GetCurrentProcess(), ret, &moduleInfo, MODULEINFO.sizeof), "Could not get module information"); 203 if(!SymLoadModuleEx(GetCurrentProcess(), null, libName.toStringz, null, cast(ulong)moduleInfo.lpBaseOfDll, moduleInfo.SizeOfImage, null, 0)) 204 { 205 import core.sys.windows.winerror; 206 207 HRESULT lastErr = GetLastError(); 208 if(lastErr != ERROR_SUCCESS) 209 { 210 import core.sys.windows.winuser; 211 MessageBoxA(null, toStringz("Failed to load the DLL named "~libName~" pdb symbols "~getWindowsErrorMessage(lastErr) ~ " " ~ lastErr.to!string), "PDB Loading Failure", MB_ICONERROR | MB_OK); 212 } 213 } 214 215 } 216 } 217 } 218 return ret; 219 } 220 221 version(Windows) private const (char)* err; 222 void* dynamicLibrarySymbolLink(void* dll, const (char)* symbolName) 223 { 224 void* ret; 225 version(NoSharedLibrarySupport) 226 ret = null; 227 else version(Windows) 228 { 229 ret = GetProcAddress(dll, symbolName); 230 if(!ret) 231 err = ("Could not link symbol "~symbolName.fromStringz).ptr; 232 } 233 else version(Posix) 234 { 235 import core.sys.posix.dlfcn : dlsym; 236 ret = dlsym(dll, symbolName); 237 } 238 return ret; 239 } 240 241 242 string dynamicLibraryError() 243 { 244 version(NoSharedLibrarySupport) 245 return "Current platform does not load dynamic libraries"; 246 else version(Windows) 247 { 248 const(char)* ret = err; 249 err = null; 250 return cast(string)fromStringz(ret); 251 } 252 else version(Posix) 253 { 254 import core.sys.posix.dlfcn; 255 return cast(string)fromStringz(dlerror()); 256 } 257 else static assert(0, "Platform not supported"); 258 } 259 260 bool dynamicLibraryRelease(void* dll) 261 { 262 version(NoSharedLibrarySupport) 263 return false; 264 else version(UWP) 265 { 266 return cast(bool)FreeLibrary(dll); 267 } 268 else version(Posix) 269 { 270 import core.sys.posix.dlfcn:dlclose; 271 return cast(bool)dlclose(dll); 272 } 273 else 274 { 275 import core.runtime; 276 version(Windows) 277 { 278 import core.sys.windows.winbase; 279 import core.sys.windows.psapi; 280 MODULEINFO moduleInfo; 281 winEnforce(() => GetModuleInformation(GetCurrentProcess(), dll, &moduleInfo, MODULEINFO.sizeof), "Could not get module information"); 282 winEnforce(() => SymUnloadModule(GetCurrentProcess(), cast(ulong)moduleInfo.lpBaseOfDll), "Could not unload PDB"); 283 } 284 return Runtime.unloadLibrary(dll); 285 } 286 }